package com.gameShare.service.misc

import com.gameShare.constances.FilePaths
import com.gameShare.entity.vo.CaptchaVo
import com.gameShare.enums.misc.ResponseCodeEnum
import com.gameShare.exceptions.BusinessException
import com.gameShare.exceptions.CaptchaException
import com.gameShare.mappers.misc.CaptchaMapper
import com.gameShare.utils.RandomUtils
import jakarta.annotation.PostConstruct
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.io.IOException
import java.util.*
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.random.Random

@Service
class CaptchaService(
    private val redisService: RedisService,
    private val filePaths: FilePaths,
    private val fileService: FileService,
    private val captchaMapper: CaptchaMapper
) {

    private val log : Logger = LoggerFactory.getLogger(CaptchaService::class.java)


    /**
     * 加载所有验证码到redis中
     */
    @OptIn(ExperimentalEncodingApi::class)
    @PostConstruct
    fun loadAllCaptcha() {
        filePaths.captchaPath.let { captchaPath ->
            fileService.readDirAllFiles(captchaPath).forEach { file ->
                try {
                    val fileBytes = file.readBytes() // 尝试读取文件内容
                    val base64Data = Base64.encode(fileBytes) // 将字节数组转换为 Base64 编码
                    val filePrefix = FileService.Companion.getFilePrefix(file.name)
                    val fileSuffix = FileService.Companion.getFileSuffix(file.name)
                    val mimeType = "image/$fileSuffix"
                    val dataUri = "data:$mimeType;base64,$base64Data"
                    redisService.saveCaptchaImage(filePrefix, dataUri) // 保存到 Redis
                } catch (e: IOException) {
                    log.error("无法读取文件: ${file.absolutePath}", e)
                    throw IOException("严重异常：无法读取验证码图片${file.absoluteFile}")
                }
            }
        }
        log.info("验证码数据加载到redis成功！")
    }

    /**
     * 生成验证码值对象
     * 从数据库随机选取题目然后写入2-3个答案然后打乱顺序记录索引准备验证
     * @return 验证码值对象
     */
    fun generateCaptcha(): CaptchaVo {
        val correctNum = Random.nextInt(1, 4)
        val randomQuestion = captchaMapper.selectRandomQuestion()

        val correctAnswers = randomQuestion.id.let { captchaMapper.selectAnswerByQuestion(it, correctNum) }
        val incorrectAnswers = randomQuestion.id.let { captchaMapper.selectRandomErrorAnswer(it, 4 - correctNum) }

        // 合并、打乱顺序并记录索引
        val (allAnswers, correctIndices) = buildList {
            addAll(correctAnswers)
            addAll(incorrectAnswers)
        }.shuffled().let { shuffledAnswers ->
            val correctIndices = mutableListOf<Int>()
            shuffledAnswers.forEachIndexed { index, answer ->
                if (correctAnswers.contains(answer)) {
                    correctIndices.add(index)
                }
            }
            Pair(shuffledAnswers, correctIndices)
        }

        val allAnswersImage : List<String?> = allAnswers.map {
            redisService.getCaptchaImage(it) ?: throw CaptchaException(it)
        }

        val key = UUID.randomUUID().toString() // 生成唯一的 key
        redisService.saveCaptchaAnswer(key, correctIndices) // 将数据存储到 Redis 中

        val captchaVo = CaptchaVo(key,randomQuestion.msg, allAnswersImage)
        return captchaVo// 返回 key 给前端
    }

    /**
     * 校验验证码
     *
     * @param key 验证码的key
     * @param answerList 用户上传的答案列表
     * @return 是否校验成功
     */
    fun verifyCaptcha(key : String, answerList : List<Int>) : Boolean{
        return redisService.getCaptchaAnswer(key)?.equals(answerList)
            ?: throw BusinessException(ResponseCodeEnum.ARGUMENT_ERROR)
    }


    // TODO 管理端上传验证码

}